import type { AsyncDataResult, Dictionary, SortCriteria, Join } from '../define/types'
import type IQuery from '../define/query'
import knex from '../connection'
import aggregate from './aggregate'

class Query implements IQuery {
 
  async selectOne(table: string, conditions: Dictionary = {}): AsyncDataResult {
    return await knex(table).where(conditions).first()
  }

  async select(table: string, conditions: Dictionary = {}, limit?: number, offset?: number, orderBy?: SortCriteria[]): AsyncDataResult {
    const totalResult = await aggregate.count(table, conditions)
    const total = totalResult[0]['count(*)'] || 0
    let query = knex(table)
    Object.keys(conditions).forEach((key) => {
      query = query.whereLike(key, `%${conditions[key]}%`)
    })
    if (limit) query = query.limit(limit)
    if (offset) query = query.offset(offset)
    if (orderBy && orderBy.length > 0) {
      orderBy.forEach((order) => {
        query = query.orderBy(order.field, order.direction)
      })
    }
    const result = await query
    return {
      data: result,
      total
    }
  }

  async selectJoin(table: string, joins: Join[], conditions: Dictionary = {}, limit?: number, offset?: number, orderBy?: SortCriteria[]): AsyncDataResult {
    const totalResult = await aggregate.count(table, conditions)
    const total = totalResult[0]?.count || 0
    let query = knex(table).where(conditions)
    if (joins && joins.length > 0) {
      joins.forEach((join) => {
        query = query.join(join.table, join.left, join.right)
      })
    }
    if (limit) query = query.limit(limit)
    if (offset) query = query.offset(offset)
    if (orderBy && orderBy.length > 0) {
      orderBy.forEach((order) => {
        query = query.orderBy(order.field, order.direction)
      })
    }
    const result = await query
    return { data: result,  total }
  }
}

export default new Query()
